<template>
  <div class="tabel-layout" :class="{ 'popup-status': isPopup }">
    <TrSearch
      ref="commonSearch"
      style="margin-bottom: 16px"
      :searchShowList="searchShowList"
      :searchHideList="searchHideList"
      :labelWidth="minSearchLabelWidth"
      :paddingStyle="searchPaddingStyle"
      :isDeepSearch="true"
      v-model="cloneSearchParams"
      @search-back="searchHandle"
      @reset-back="resetParamsHandle"
      v-if="searchShowList.length > 0"
    />
    <div class="divider-line" v-if="isNeedLine"></div>
    <div class="table-content-wrap">
      <div
        class="slot-btn"
        :class="{ 'slot-start': slotStart }"
        v-if="filterBtnList(btnList).length > 0"
      >
        <div
          class="btn-item"
          :class="item.color"
          v-for="(item, index) in filterBtnList(btnList)"
          :key="index"
          @click="emitHandle(1, item.option, item)"
        >
          {{ item.label }}
        </div>
      </div>
      <div class="popup-table-wrap" v-if="tableColumn.length > 0">
        <el-table
          ref="elTable"
          class="commom-table-banner"
          border
          :key="updateKeys"
          :data="tableData"
          :height="tableHeight"
          :row-class-name="tableRowClassName"
          :row-key="rowKeyStr"
          header-cell-class-name="live-header-cell"
          :lazy="lazy"
          :load="lazy ? loadFun : undefined"
          :tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
          @selection-change="handleSelectionChange"
        >
          <el-table-column
            v-if="isNeedSelection"
            type="selection"
            width="60"
            :reserve-selection="reserveSelection"
            :selectable="checkSelectable"
          >
          </el-table-column>
          <el-table-column
            v-if="isNeedIndex"
            type="index"
            width="80"
            label="序号"
          >
          </el-table-column>
          <el-table-column
            v-for="(item, index) in tableColumn"
            :key="index"
            :label="item.label"
            :width="item.width || 160"
            :fixed="item.fixed ? item.fixed : undefined"
            :sortable="item.sortable"
            :sort-method="
              item.sortMethod ||
              ((a, b) => {
                return a[item.value] - b[item.value];
              })
            "
            :show-overflow-tooltip="
              item.type != 'option' &&
              item.type != 'input' &&
              item.type != 'image'
            "
            :type="item.columnType || undefined"
          >
            <template slot-scope="scope">
              <div
                class="row-label"
                v-if="item.type == 'text'"
                :style="{ color: scope.row[`${item.value}Color`] }"
                @click="clickColumnHandle(scope.row, item)"
              >
                {{ scope.row[item.value] }}
              </div>
              <div class="row-label" v-if="item.type == 'switch'">
                <el-switch
                  v-model="scope.row[item.value]"
                  active-color="#0087d6"
                  @change="changeSwitchHandle($event, scope.row)"
                ></el-switch>
              </div>
              <div class="row-input" v-if="item.type == 'input'">
                <el-input
                  v-model="scope.row[item.value]"
                  :placeholder="item.placeholder ? item.placeholder : '请输入'"
                  :maxlength="item.maxlength"
                  :type="item.inputType || 'text'"
                  :max="item.max"
                  :min="item.min"
                  :disabled="item.disabled"
                  @blur="inputBlurHandle(item, scope)"
                ></el-input>
              </div>
              <template v-if="item.type == 'slot'">
                <slot
                  :name="item.slotName"
                  v-bind="scope.row"
                  :row="scope.row"
                  :prop="item.value"
                ></slot>
              </template>
              <div class="option-wrap" v-if="item.type == 'option'">
                <template
                  v-for="(sItem, sIndex) in filterBtnList(item.showBtnList)"
                >
                  <div
                    :key="sIndex"
                    class="show-btn"
                    @click="emitHandle(2, sItem.option, scope.row)"
                    v-if="!scope.row[`isShow${sItem.option}`]"
                  >
                    {{ sItem.label }}
                  </div>
                </template>
                <el-tooltip effect="light" placement="bottom">
                  <template slot="content">
                    <template
                      v-for="(sItem, sIndex) in filterBtnList(item.hideBtnList)"
                    >
                      <div
                        v-if="!scope.row[`isShow${sItem.option}`]"
                        class="show-btn"
                        :key="sIndex"
                        @click="emitHandle(2, sItem.option, scope.row)"
                      >
                        {{ sItem.label }}
                      </div>
                    </template>
                  </template>
                  <span
                    class="show-btn"
                    v-if="
                      !scope.row['isShowHideBtnList'] &&
                      filterBtnList(item.hideBtnList).length > 0
                    "
                    >更多</span
                  >
                </el-tooltip>
              </div>
              <template v-if="item.columnType == 'expand'">
                <div class="expand-wrap">
                  <TrTable
                    isPopup
                    isInEmit
                    :row-class-name="tableRowClassName"
                    :rowKeyStr="(expandObj && expandObj.rowKeyStr) || rowKeyStr"
                    header-cell-class-name="live-header-cell"
                    :expandObj="expandObj"
                    :tableData="
                      scope.row[
                        (expandObj && expandObj.childrenWord) ||
                          'expandChildren'
                      ]
                    "
                    :isNeedIndex="expandObj && expandObj.isNeedIndex"
                    :tableColumn="expandObj && expandObj.tableColumn"
                    :tableHeight="
                      (expandObj && expandObj.tableHeight) || tableHeight
                    "
                    :isNeedPagination="
                      (expandObj && expandObj.isNeedPagination) || false
                    "
                    @in-emit-back="emitBackHandle"
                  ></TrTable>
                </div>
              </template>
              <template v-if="item.type == 'image'">
                <div class="image-list">
                  <div
                    class="iamge-wrap"
                    v-for="(iItem, iIndex) in getImageList(
                      scope.row,
                      item
                    ).slice(0, 4)"
                    :key="iIndex"
                  >
                    <el-image
                      class="image-item"
                      lazy
                      :src="iItem"
                      :preview-src-list="getImageList(scope.row, item)"
                    >
                    </el-image>
                    <div
                      class="over-hide"
                      v-if="
                        iIndex == 3 && getImageList(scope.row, item).length > 5
                      "
                    >
                      +{{ getImageList(scope.row, item).length - 4 }}
                    </div>
                  </div>
                </div>
              </template>
            </template>
          </el-table-column>
          <div class="empty-block" slot="empty">
            <img src="@/assets/common/empty_icon.png" class="empty-table-img" />
          </div>
        </el-table>
      </div>
      <TrFooter
        v-model="cloneSearchParams"
        ref="footPagination"
        :isDeepSearch="true"
        v-if="isNeedPagination"
        :sizeWord="sizeWord"
        :currentWord="currentWord"
        :requestName="requestName"
        :total="total"
        @footer-search="footerSearch"
      />
    </div>
  </div>
</template>

<script>
// import { xor, debounce } from "lodash-es";
import _ from "lodash";
import TrSearch from "@/components/Tr-search/Tr-search.vue";
import TrFooter from "@/components/Tr-footer/Tr-footer.vue";
import { getStore } from "@/utils/store";
export default {
  name: "TrTable",
  components: {
    TrFooter,
    TrSearch,
  },
  props: {
    isNeedInit: {
      type: Boolean,
      default: true,
    },
    checkSelectable: {
      default: undefined,
    },
    searchPaddingStyle: {
      type: String,
    },
    isNeedIndex: {
      type: Boolean,
      default: false,
    },
    slotStart: {
      type: Boolean,
      default: false,
    },
    isNeedLine: {
      type: Boolean,
      default: false,
    },
    isPopup: {
      type: Boolean,
      default: false,
    },
    isInEmit: {
      type: Boolean,
      default: false,
    },
    reserveSelection: {
      type: Boolean,
      default: true,
    },
    rowKeyStr: {
      type: String,
      default: "id",
    },
    lazy: {
      type: Boolean,
      default: false,
    },
    loadFun: {
      type: Function,
    },
    btnList: {
      type: Array,
      default: () => [],
    },
    searchShowList: {
      type: Array,
      default: () => [],
    },
    searchHideList: {
      type: Array,
      default: () => [],
    },
    value: {
      type: [Object, Array, String],
    },
    tableData: {
      type: Array,
      default: () => [],
    },
    tableColumn: {
      type: Array,
      default: () => [],
    },
    isNeedPagination: {
      type: Boolean,
      default: true,
    },
    tableHeight: {
      type: String,
      default: "100%",
    },
    requestName: {
      type: String,
      default: "",
    },
    minSearchLabelWidth: {
      type: Number,
      default: 72,
    },
    total: {
      type: [Number, String],
      default: 0,
    },
    isNeedSelection: {
      type: Boolean,
      default: false,
    },
    tableRowClassName: {
      type: Function,
    },
    sizeWord: {
      type: String,
      default: "size",
    },
    currentWord: {
      type: String,
      default: "current",
    },
    checkedList: {
      type: Array,
      default: () => [],
    },
    expandObj: {
      type: Object,
      default: () => {},
    },
  },
  data: () => ({
    selectionList: [],
    cloneSearchParams: {},
    currentPage: 1,
    pageSize: 10,
    permissionObject: getStore({ name: "permission" }),
    userInfo: getStore({ name: "userInfo" }),
    routeName: "",
    updateKeys: 1,
  }),
  watch: {
    value: {
      handler(val) {
        if (val[this.currentWord] == 1) {
          this.$refs.footPagination.currentPage = 1;
        }
      },
      deep: true,
    },
    tableData: {
      handler(newVal) {
        if (!this.checkedList.length) return;
        this.$nextTick(() => {
          newVal.forEach((item) => {
            if (this.checkedList.includes(item[this.rowKeyStr])) {
              this.$refs.elTable.toggleRowSelection(item, true);
            } else {
              this.$refs.elTable.toggleRowSelection(item, false);
            }
          });
        });
      },
      deep: true,
      immediate: true,
    },
    checkedList: {
      handler(newVal) {
        if (!newVal.length) {
          this.clearSelect();
          return;
        }
        this.$nextTick(() => {
          this.tableData.forEach((item) => {
            if (newVal.includes(item[this.rowKeyStr])) {
              this.$refs.elTable.toggleRowSelection(item, true);
            } else {
              this.$refs.elTable.toggleRowSelection(item, false);
            }
          });
        });
      },
      deep: true,
      immediate: true,
    },
  },
  methods: {
    updateKey() {
      this.updateKeys++;
    },
    getImageList(row, item) {
      if (!row[item.value]) return [];
      return row[item.value];
    },
    filterBtnList(list) {
      if (this.userInfo.role_name.indexOf("admin") > -1)
        return list ? list : [];
      if (!list || !list.length || !this.permissionObject) return [];
      let perList = this.permissionObject[this.routeName];
      if (!perList) return [];
      let newBtnList =
        list.filter((item) => perList.includes(item.option)) || [];
      return newBtnList;
    },
    clearLazyNode(id) {
      this.$refs.elTable.store.states.lazyTreeNodeMap[id] = [];
    },
    changeSwitchHandle(val, item) {
      this.$emit("change-switch", item);
    },
    clickColumnHandle(val, item) {
      this.$emit("column-back", Object.assign({}, val, item));
    },
    emitHandle(index, type, val) {
      if (this.isInEmit) {
        this.$emit("in-emit-back", type, JSON.parse(JSON.stringify(val)));
        return;
      }
      if (index == 1) {
        if (val.isRelaTable && this.selectionList.length < 1) {
          this.$message.warning(this.$t("tip.lessOne"));
        } else {
          this.$emit(type, type);
        }
        return;
      }
      if (index == 2) this.$emit(type, JSON.parse(JSON.stringify(val)));
    },
    emitBackHandle(type, val) {
      this.$emit(type, type, val);
    },
    handleSelectionChange(val) {
      this.selectionList = val;
      this.debouncedChange();
      this.$emit("select-change", val);
    },
    debouncedChange: _.debounce(function () {
      this.updateCheckList();
    }, 100),
    updateCheckList() {
      // 当前已选中
      const selectIds = new Set(
        this.selectionList.map((item) => item[this.rowKeyStr])
      );
      // 与传进来的差异Id
      const diffIds = new Set(_.xor([...selectIds], this.checkedList));
      // 当前表格的Id
      const tableIds = new Set(
        this.tableData.map((item) => item[this.rowKeyStr])
      );
      // 找出删除项
      const deleteIds = [...diffIds].filter(
        (item) =>
          this.checkedList.includes(item) &&
          tableIds.has(item) &&
          !selectIds.has(item)
      );
      // 去重并计算新列表
      const result = new Set([...selectIds, ...this.checkedList]);
      deleteIds.forEach((id) => result.delete(id));
      // 将结果转为数组并更新
      this.$emit("update:checkedList", [...result]);
    },
    footerSearch() {
      this.$emit("input", this.cloneSearchParams);
      this.commonSearch();
    },
    commonSearch() {
      this.$nextTick(() => {
        this.findAndExecuteFunction(this.requestName);
      });
    },
    searchHandle() {
      this.cloneSearchParams[this.sizeWord] =
        this.$refs.footPagination.pageSize;
      this.$emit("input", this.cloneSearchParams);
      this.$refs.footPagination.cloneParams = this.cloneSearchParams;
      this.$refs.footPagination.currentPage = 1;
      this.commonSearch();
    },
    searchCommon() {
      if (this.isNeedSelection) this.clearSelect();
      this.$refs.footPagination.currentPage = 1;
      this.$refs.footPagination.pageSize =
        this.cloneSearchParams[this.sizeWord];
      this.commonSearch();
    },
    resetParamsHandle() {
      this.$emit("input", this.cloneSearchParams);
      this.$emit("reset-back");
      this.searchCommon();
    },
    clearSelect() {
      this.$refs?.elTable?.clearSelection();
    },
    doLayout() {
      this.$refs?.elTable?.doLayout();
    },
    initSearch() {
      this.$refs?.commonSearch?.searchHandle();
    },
    findAndExecuteFunction(funcName) {
      let parent = this.$parent;
      while (parent) {
        if (typeof parent[funcName] === "function") {
          parent[funcName]();
          return;
        }
        parent = parent.$parent;
      }
    },
    inputBlurHandle(item, scope) {
      this.$emit("input-back", item, scope.row, scope.$index);
    },
    // setCenter(number) {
    //   let totalWidth = Number(this.$refs.elTable.bodyWidth.replace("px", ""));
    //   let offWidth = this.$refs.elTable.$el.offsetWidth;
    //   this.$nextTick(() => {
    //     this.$refs.elTable.bodyWrapper.scrollLeft =
    //       number !== undefined ? number : (totalWidth - offWidth) / 2;
    //   });
    // },
    // 更新树形类型节点
    updateKeyChildrenById(parentId, list) {
      this.$set(
        this.$refs.elTable.store.states.lazyTreeNodeMap,
        parentId,
        list
      );
    },
  },
  created() {
    this.routeName = this.$route.path.split("/").pop();
    this.cloneSearchParams = this.value;
  },
  mounted() {
    this.$nextTick(() => {
      if (this.isNeedInit) this.initSearch();
    });
  },
};
</script>

<style lang="scss" scoped>
::v-deep.row-input {
  input::-webkit-outer-spin-button,
  input::-webkit-inner-spin-button {
    -webkit-appearance: none;
  }
  input[type="number"] {
    -moz-appearance: textfield;
  }
}
::v-deep.popup-status {
  .table-content-wrap {
    .el-table {
      .el-table__body-wrapper {
        max-height: 391px;
        height: auto !important;
      }
    }
  }
}
.tabel-layout {
  display: flex;
  flex-direction: column;
  flex: 1;
  overflow: hidden;
  .divider-line {
    background-color: #e7e7e7;
    height: 1px;
    margin-bottom: 24px;
  }
  .slot-btn {
    min-height: 32px;
    display: flex;
    justify-content: flex-end;
    margin-bottom: 24px;
    .btn-item {
      height: 32px;
      border: 1px solid #0087d6;
      display: flex;
      align-items: center;
      justify-content: center;
      margin-left: 16px;
      padding: 0 15px;
      border-radius: 3px;
      font-size: 14px;
      cursor: pointer;
      transition: all 0.3s;
      &.white {
        background: #fff;
        color: #0087d6;
        &:hover {
          color: #4e52da;
          border: 1px solid #4e52da;
        }
      }
      &.blue {
        background: #0087d6;
        color: #fff;
        &:hover {
          background: #4e52da;
          border: 1px solid #4e52da;
        }
      }
      &:first-child {
        margin-left: 0;
      }
    }
    &.slot-start {
      justify-content: flex-start;
    }
  }
  .table-content-wrap {
    background-color: #fff;
    border-radius: 8px;
    padding: 24px 24px 0 24px;
    display: flex;
    flex-direction: column;
    flex: 1;
    overflow: hidden;
  }
  .popup-table-wrap {
    flex: 1;
    overflow: hidden;

    .commom-table-banner {
      width: 100%;
    }
  }
  &.popup-status {
    .table-content-wrap {
      border-radius: 0;
      padding: 0;
    }
  }
}
.expand-wrap {
  padding: 0 24px 24px 24px;
  background-color: #f8f8f8;
}
.image-list {
  display: flex;
  align-items: content;
  line-height: 0;
}
.iamge-wrap {
  position: relative;
  margin-right: 4px;
  &:last-child {
    margin-right: 0;
  }
  .over-hide {
    position: absolute;
    border-radius: 2px;
    pointer-events: none;
    cursor: pointer;
    width: 100%;
    height: 100%;
    z-index: 2;
    top: 0;
    left: 0;
    color: #fff;
    font-size: 12px;
    display: flex;
    align-items: center;
    justify-content: center;
    background-color: rgba(0, 0, 0, 0.5);
  }
  &:hover {
    .over-hide {
      display: none;
    }
  }
}
.image-item {
  position: relative;
  cursor: pointer;
  width: 32px;
  height: 32px;
  border-radius: 2px;
  &::before {
    transition: all 0.3s;
    pointer-events: none;
    position: absolute;
    display: block;
    opacity: 0;
    content: "";
    background-color: rgba(0, 0, 0, 0.5);
    height: 100%;
    width: 100%;
    border-radius: 2px;
  }
  &::after {
    transition: all 0.3s;
    pointer-events: none;
    position: absolute;
    opacity: 0;
    z-index: 1;
    display: block;
    content: "";
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    background: url("~@/assets/common/eye_white.png");
    background-size: contain;
    height: 16px;
    width: 16px;
  }
  &:hover {
    &::before,
    &::after {
      opacity: 1;
    }
  }
}
</style>
